<template>
	<view class="vi_tabs" :class="'vi_'+setting.type">
		<view class="vi_tabs_slot">
			<slot name="left" />
		</view>
		<scroll-view :id="id" class="vi_tabs_content" @scroll="scroll"
			:style="{'height':`calc(2em + ${setting.tipHeight})`}"
			scroll-x
			:scroll-with-animation="!!track"
			:scroll-left="syncLeft">
			<view class="vi_tabs_tabBar" :class="[tabClass||'', {'vi_tabs_center':isCenter}]">
				<view class="vi_tabs_item" v-for="(item, index) in inList" :key="index"
					:style="itemStyle"
					@click="tabClick(item)">
					<vi-style-controller
						control="text"
						:type="setting.type"
						:color="color"
						:textColor="textColor"
						:disabled="disabled"
						:active="item.value==inValue">
						<text class="vi_tabs_text" :class="{'vi_bold':textBold&&item.value==inValue}">
							{{item.name}}
						</text>
					</vi-style-controller>
					<view class="vi_tabs_tip" :style="{'width': setting.tipWidth}">
						<view class="vi_tabs_actBox" :class="{'vi_tabs_active':item.value==inValue}">
							<vi-style-controller
								control="background"
								:type="setting.type"
								:color="color"
								:disabled="disabled"
								width="100%"
								:height="setting.tipHeight"
								active>
							</vi-style-controller>
						</view>
					</view>
				</view>
			</view>
		</scroll-view>
		<view class="vi_tabs_slot">
			<slot name="right" />
		</view>
	</view>
</template>

<script>
	export default {
		name:"viTabs",
		model:{
			prop:"value",
			event:"input"
		},
		props:{
			dataList:{
				type:Array,
				default:()=>[
					// {
					// 	name:"标题",
					// 	value:0,
					// }
				]
			},
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:""
			},
			textColor:{
				type:[String,null],
				default:""
			},
			textBold:{
				type:[Boolean,null],
				default:false
			},
			value:{
				type:[String,Number,null],
				default:null
			},
			disabled:{
				type:[Boolean,null],
				default:false
			},
			readOnly:{
				type:[Boolean,null],
				default:false
			},
			tipWidth:{
				type:[String,null],
				default:null
			},
			tipHeight:{
				type:[String,Number,null],
				default:null
			},
			//tab项宽度
			tabWidth:{
				type:[String,null],
				default:null
			},
			//tab两端间距，两个tab之间距离为该值乘2
			tabSpace:{
				type:[String,null],
				default:null
			},
			track:{
				type:[Boolean,null],
				default:false
			},
			tabClass:{
				type:[String,null],
				default:""
			}
		},
		data() {
			return {
				id:null,
				inValue:"",
				inList:null,
				scrollLeft:0,
				syncLeft:0,
				barW:0,
			}
		},
		computed:{
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					tabWidth: this.$api.isDefined(this.tabWidth)? this.tabWidth :"equal",
					tipWidth: this.$api.isDefined(this.tipWidth)? this.tipWidth :"75%",
					tipHeight: this.$api.isDefined(this.tipHeight)? this.tipHeight :"2px",
					tabSpace: this.$api.isDefined(this.tabSpace)? this.tabSpace :"0.5em",
				}
			},
			itemStyle(){
				let res = {
					"width": "auto",
				};
				let tabWidth = this.setting.tabWidth;
				if(tabWidth&&tabWidth!="center"){
					if(tabWidth=="equal"){
						res["width"] = 1/this.inList.length *100 +"%"
					}else{
						res["width"] = tabWidth
					}
				}
				let tabSpace = this.setting.tabSpace;
				if(tabSpace){
					res["padding-left"] = tabSpace;
					res["padding-right"] = tabSpace;
				}
				return this.$api.objToStr(res)
			},
			isCenter(){
				let lastItem = this.inList[this.inList.length-1];
				return this.setting.tabWidth=="center" && (lastItem.left+lastItem.width < this.barW)
			}
		},
		methods: {
			tabClick(item){
				if(!this.disabled&&!this.readOnly && item.value != this.inValue){
					this.inValue = item.value;
					this.$emit("input", this.inValue);
					this.$emit("change", this.inValue, item);
					if(this.track){
						this.syncLeft = this.scrollLeft;
						this.$nextTick(()=>{
							this.syncLeft = (item.width - this.barW)/2 + item.left
						})
					}
				}
			},
			getPoint(callback){
				if(!this.id){
					return
				}
				let done = 0;
				const query = uni.createSelectorQuery().in(this);
				query.selectAll(`#${this.id} .vi_tabs_item`).boundingClientRect(data => {
					for(let i=0; i<this.inList.length; i++){
						if(i>0){
							this.inList[i]["left"] = data[i-1].left + data[i-1].width;
						}else{
							this.inList[i]["left"] = data[i].width;
						}
						this.inList[i]["width"] = data[i].width;
					}
					done +=1;
					if(done==2 && this.$api.isFunction(callback)){
						callback()
					}
				}).exec();
				
				const query1 = uni.createSelectorQuery().in(this);
				query1.select(`#${this.id}`).boundingClientRect(data => {
					this.barW = data.width;
					done +=1;
					if(done==2 && this.$api.isFunction(callback)){
						callback()
					}
				}).exec();
			},
			scroll(e){
				this.scrollLeft = e.detail.scrollLeft
			}
		},
		watch:{
			"value":{
				immediate:true,
				handler(newVal){
					this.inValue = newVal
				}
			},
			"dataList":{
				immediate:true,
				handler(newVal){
					this.inList = newVal ||[];
					if(this.track){
						this.getPoint();
					}
				}
			}
		},
		created() {
			this.id = `tbs${Math.ceil(Math.random() * 10e10).toString(36)}`
		},
		mounted() {
			if(this.track){
				this.getPoint(()=>{
					let item = this.$api.arrFind(this.inList, {key:"value", value:this.inValue, format:"item"})
					if(item){
						this.syncLeft = (item.width - this.barW)/2 + item.left
					}
				})
			}
		}
	}
</script>

<style lang="scss">
$transition:.3s;
.vi_tabs{
	position: relative;
	display: flex;
	justify-content: center;
	align-items: center;
	.vi_tabs_slot{
		flex-shrink: 0;
	}
	.vi_tabs_content{
		flex-grow: 1;
		position: relative;
		.vi_tabs_tabBar{
			width: 100%;
			display: flex;
			justify-content: flex-start;
			align-items: center;
			position: absolute;
			&.vi_tabs_center{
				justify-content:center
			}
		}
	}
	.vi_tabs_item{
		flex-shrink: 0;
		position: relative;
		line-height: 1;
		padding: 0.25em 0;
		transition: $transition;
		box-sizing: border-box;
		.vi_tabs_text{
			white-space: nowrap;
		}
		.vi_tabs_tip{
			margin: 0.5em auto 0;
			display: flex;
			justify-content: center;
			.vi_tabs_actBox{
				flex-shrink: 0;
				width: 0;
				transition: $transition;
				animation: vi-tabs-rubberBand-leave 0.1s;
				animation-fill-mode: forwards;
				&.vi_tabs_active{
					width: 100%;
					animation: vi-tabs-rubberBand $transition linear;
				}
			}
		}
	}
}
.vi_bold{
	font-weight: bold;
}

@keyframes vi-tabs-rubberBand{
	from{ width: 0;}
	40%{ width: 120%;}
	60%{ width: 80%;}
	to{ width: 100%;}
}
@keyframes vi-tabs-rubberBand-leave{
	from{ width: 100%;}
	to{ width: 0%;}
}
</style>
